/** @file

  Copyright (C) 2022 - 2023, Phytium Technology Co., Ltd. All rights reserved.<BR>

  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include <Uefi.h>
#include <Protocol/PciIo.h>
#include <Library/UefiLib.h>
#include <Library/DebugLib.h>
#include <Library/IoLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/BaseMemoryLib.h>
//[gliu-0009]
//#include "AdvancedConfigData.h"
#include <ChipX100ConfigData.h>
#include <SetupConfig.h>
#include <Library/KlSetupVarRWLib.h>
#include <Protocol/DevicePathToText.h>
//[gliu-0009]
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/OemServicesLib.h> //[jdzhang-0016]

#if FixedPcdGetBool(PcdX100PortControl)

/*
 * 0 - not existed
 * 1 - existed
 */
BOOLEAN
EFIAPI
IsX100Existed (
  VOID
  )
{
  UINT32                      Status;
  UINTN                       NumOfPciHandles;
  EFI_HANDLE                  *HandleBuffer;
  EFI_PCI_IO_PROTOCOL         *PciIo;
  UINT32                      Index;
  UINT16                      DeviceID;
  UINT16                      VendorID;

  Status = 0;
  NumOfPciHandles = 0;
  HandleBuffer = NULL;
  Status = gBS->LocateHandleBuffer (
                  ByProtocol,
                  &gEfiPciIoProtocolGuid,
                  NULL,
                  &NumOfPciHandles,
                  &HandleBuffer
                  );
  if (EFI_ERROR (Status)) {
    return 0;
  }
  DEBUG ((EFI_D_INFO, "Pci handles number is %d\n", NumOfPciHandles));

  for (Index = 0; Index < NumOfPciHandles; Index ++) {
    Status = gBS->HandleProtocol (
                    HandleBuffer[Index],
                    &gEfiPciIoProtocolGuid,
                    (VOID **)&PciIo
                    );
    if (!EFI_ERROR (Status)) {
      PciIo->Pci.Read (
                   PciIo,
                   EfiPciIoWidthUint16,
                   0x0,
                   1,
                   &VendorID
                   );
      PciIo->Pci.Read (
                   PciIo,
                   EfiPciIoWidthUint16,
                   0x2,
                   1,
                   &DeviceID
                   );
      //DEBUG ((EFI_D_INFO, "Device ID : 0x%04x, Vendor ID : 0x%04x\n", DeviceID, VendorID));
      if ((DeviceID == 0xdc20) && (VendorID == 0x1db7)) {
        return 1;
      }
    }
  }
  return 0;
}


EFI_STATUS
X100ConfigParaInit (
  IN SYSTEM_SETUP_CONFIGURATION  *Configuration
  )
{
  EFI_STATUS        Status = 0;
  //[gliu-0031]add-start
  X100_CONFIG *     X100ConfigDataPtr;
  X100_CONFIG *     X100ConfigDataTemp;
  //[gliu-0031]add-end
  UINT16            VarChangeFlag;

  if (Configuration == NULL) {
    DEBUG((EFI_D_ERROR, "X100ConfigParaInit Configuration is error\n"));
    return Status;
  }
  VarChangeFlag = 0;
  X100ConfigDataTemp = AllocatePool(sizeof(X100_CONFIG));//[gliu-0031]
  CopyMem(X100ConfigDataTemp,
      &Configuration->X100Config,
      sizeof(X100_CONFIG)); //[gliu-0031]

  X100ConfigDataPtr = &Configuration->X100Config;
  X100ConfigDataPtr->X100IsExisted = IsX100Existed();
  InitX100Version();

  // Judge whether the storage parameters change
  //[gliu-0031]add-start
  if (CompareMem(X100ConfigDataTemp,
          &Configuration->X100Config,
          sizeof(X100_CONFIG))
      != 0) {
  //[gliu-0031]add-end
    VarChangeFlag = 1;
  }

  if (VarChangeFlag > 0) {
    VarChangeFlag = 0;
    Status = KlSetupVarWrite(Configuration);
    ASSERT_EFI_ERROR(Status);
  }
  return Status;
}
//[jckuang-0003]


EFI_STATUS
EFIAPI
GetDpChannel (
  VOID
  )
{
  EFI_STATUS                  Status;
  UINTN                       NumOfPciHandles;
  EFI_HANDLE                  *HandleBuffer;
  X100_PCI_INFO               X100PciInfo;
  EFI_PCI_IO_PROTOCOL         *PciIo;
  UINT32                      Index;
  UINT16                      DeviceID;
  UINT16                      VendorID;
  UINT16                      SubsystemID;
  UINT8                       DpChannel = 0;
  UINTN                       VarSize;

  NumOfPciHandles = 0;
  HandleBuffer = NULL;
  Status = gBS->LocateHandleBuffer (
                  ByProtocol,
                  &gEfiPciIoProtocolGuid,
                  NULL,
                  &NumOfPciHandles,
                  &HandleBuffer
                  );
  if (EFI_ERROR (Status)) {
    return Status;
  }
  DEBUG ((EFI_D_INFO, "Pci handles number is %d\n", NumOfPciHandles));

  for (Index = 0; Index < NumOfPciHandles; Index ++) {
    Status = gBS->HandleProtocol (
                    HandleBuffer[Index],
                    &gEfiPciIoProtocolGuid,
                    (VOID **)&PciIo
                    );
    if (!EFI_ERROR (Status)) {
      PciIo->Pci.Read (
                   PciIo,
                   EfiPciIoWidthUint16,
                   0x0,
                   1,
                   &VendorID
                   );
      PciIo->Pci.Read (
                   PciIo,
                   EfiPciIoWidthUint16,
                   0x2,
                   1,
                   &DeviceID
                   );
      DEBUG ((EFI_D_INFO, "Device ID : 0x%04x, Vendor ID : 0x%04x\n", DeviceID, VendorID));
      if ((DeviceID == 0xdc22) && (VendorID == 0x1db7)) {
        PciIo->Pci.Read (
                   PciIo,
                   EfiPciIoWidthUint16,
                   0x2E,
                   1,
                   &SubsystemID
                   );
        DEBUG((EFI_D_INFO, "Subsystem ID:0x%x\n", SubsystemID));
        for (Index = 0; Index < 3; Index++) {
            if((SubsystemID >> Index) & 0x1) {
                DpChannel++;
            }
        }
        VarSize = sizeof(X100_PCI_INFO);
        Status = gRT->GetVariable (
                        VAR_X100_PCI_INFO,
                        &gX100PciInfoVarGuid,
                        NULL,
                        &VarSize,
                        &X100PciInfo
                  );
        X100PciInfo.DpChannel = DpChannel;
        Status = gRT->SetVariable (
                        VAR_X100_PCI_INFO,
                        &gX100PciInfoVarGuid,
                        PLATFORM_SETUP_VARIABLE_FLAG,
                        sizeof (X100_PCI_INFO),
                        &X100PciInfo
                  );
        break;
      }
    }
  }
  return Status;
}

UINT32
SetDevicePowerState (
  EFI_PCI_IO_PROTOCOL  *PciIo,
  UINT8                PowerState
  )
{
  UINT8  Point;
  UINT8  PointNew;
  UINT8  CapId;
  UINT8  Temp;

  PciIo->Pci.Read (
               PciIo,
               EfiPciIoWidthUint8,
               0x34,
               1,
               &PointNew
               );
  while(1) {
    DEBUG ((EFI_D_INFO, "Pci Cap Point : 0x%02x\n", PointNew));
    if (PointNew == 0x0) {
      break;
    }
    Point = PointNew;
    PciIo->Pci.Read (
                 PciIo,
                 EfiPciIoWidthUint8,
                 Point,
                 1,
                 &CapId
                 );
    PciIo->Pci.Read (
                 PciIo,
                 EfiPciIoWidthUint8,
                 Point + 1,
                 1,
                 &PointNew
                 );
    DEBUG ((EFI_D_INFO, "CapId : 0x%02x, point next : 0x%02x\n", CapId, PointNew));
    if (CapId == 0x01) {
      PciIo->Pci.Read (
                   PciIo,
                   EfiPciIoWidthUint8,
                   Point + 4,
                   1,
                   &Temp
                   );
      DEBUG ((EFI_D_INFO, "power state : 0x%02x\n", Temp));
      Temp &= 0xFC;
      Temp |= PowerState;
      PciIo->Pci.Write (
                   PciIo,
                   EfiPciIoWidthUint8,
                   Point + 4,
                   1,
                   &Temp
                   );
    }
  }
  return 0;
}

STATIC
EFI_STATUS
SetX100ConfigToDc (
  IN X100_CONFIG     *Config,//[gliu-0031]
  IN EFI_PCI_IO_PROTOCOL  *PciIo
  )
{
  UINT32      Index;
  UINT8       DpUseStatus;
  UINT8       DownSpreadStatus;
  UINT32      Data;
  EFI_STATUS  Status;
  UINT32      Temp;

  Status = EFI_SUCCESS;
  DownSpreadStatus = 0;
  Temp = 0x03;
  PciIo->Pci.Write (
               PciIo,
               EfiPciIoWidthUint8,
               0x4,
               1,
               &Temp
               );
  PciIo->Pci.Read (
               PciIo,
               EfiPciIoWidthUint32,
               0x2C,
               1,
               &Data
               );
  DpUseStatus = (UINT8)(Data >> 16);
  for (Index = 0; Index < 3; Index++) {
    Config->X100DpConfig[Index].IsUsed = (DpUseStatus >> Index) & 0x1;
    DownSpreadStatus |= (Config->X100DpConfig[Index].DownSpreadEnable << Index);
    DEBUG ((EFI_D_INFO, "Config->X100DpConfig[%d].DownSpreadEnable : %x\n", Index, Config->X100DpConfig[Index].DownSpreadEnable));
    DEBUG ((EFI_D_INFO, "Config->X100DpConfig[%d].IsUsed : %x\n", Index, Config->X100DpConfig[Index].IsUsed));
  }
  DEBUG ((EFI_D_INFO, "X100 Dp DownSpread Config : 0x%x\n", DownSpreadStatus));

  Status = PciIo->Mem.Read (
                        PciIo,
                        EfiPciIoWidthUint32,
                        0,        //Point to Bar 0(MMIO base address),
                        0x4048,
                        1,
                        &Data
                        );
  if (Status != EFI_SUCCESS) {
    DEBUG ((EFI_D_INFO, "Get Dp 4048 reg Failed!\n"));
    return Status;
  }
  DEBUG ((EFI_D_INFO, "Data : %x\n", Data));
  Data &= ~(0x7 << 3);
  DEBUG ((EFI_D_INFO, "Data : %x\n", Data));
  Data |= (DownSpreadStatus << 3);
  DEBUG ((EFI_D_INFO, "Data : %x\n", Data));
  Status = PciIo->Mem.Write (
                        PciIo,
                        EfiPciIoWidthUint32,
                        0,      //Point to Bar 0(MMIO base address)
                        0x4048,
                        1,
                        &Data
                        );
  if (Status != EFI_SUCCESS) {
    DEBUG ((EFI_D_INFO, "Get Dp DownSpread Ctrl Failed!\n"));
    return Status;
  }
  Temp = 0x0;
  PciIo->Pci.Write (
               PciIo,
               EfiPciIoWidthUint8,
               0x4,
               1,
               &Temp
               );
  return Status;
}

#if 0
EFI_STATUS
ControlX100DevEnable (
  VOID
)
{
  UINT32                      Status;
  UINTN                       NumOfPciHandles;
  EFI_HANDLE                  *HandleBuffer;
  EFI_PCI_IO_PROTOCOL         *PciIo;
  UINT32                      Index;
  UINT16                      DeviceID;
  UINT16                      VendorID;
  UINTN                       Seg;
  UINTN                       Bus;
  UINTN                       Func;
  UINTN                       Dev;
  X100_CONFIG                 X100ConfigData;
  UINTN                       VarSize;
  X100_PCI_INFO               X100PciInfo;
  UINT32                      Num;
  UINT8                       Temp;
  UINT32                      SataPi;

  ZeroMem (&X100PciInfo, sizeof(X100_PCI_INFO));
  X100PciInfo.UsbSwitch.Enable = 1;
  X100PciInfo.SataSwitch.Enable = 1;
  VarSize = sizeof(X100_CONFIG);
  Status = 0;
  NumOfPciHandles = 0;
  HandleBuffer = NULL;

  Status = gRT->GetVariable (
                  VAR_X100_CONFIG,
                  &gAdvancedX100VarGuid,
                  NULL,
                  &VarSize,
                  &X100ConfigData
                  );
  if (Status != EFI_SUCCESS) {
    return Status;
  }

  for (Num = 0; Num < 4; Num++) {
    X100ConfigData.SataPort[Num].IsUsed = 0;
  }

  Status = gBS->LocateHandleBuffer (
                  ByProtocol,
                  &gEfiPciIoProtocolGuid,
                  NULL,
                  &NumOfPciHandles,
                  &HandleBuffer
                  );
  if (EFI_ERROR (Status)) {
    return Status;
  }
  DEBUG ((EFI_D_INFO, "Pci handles number is %d\n", NumOfPciHandles));
  DEBUG ((EFI_D_INFO, "Config->X100DpConfig[0].DownSpreadEnable : %x\n", X100ConfigData.X100DpConfig[0].DownSpreadEnable));
  DEBUG ((EFI_D_INFO, "Config->X100DpConfig[0].IsUsed : %x\n", X100ConfigData.X100DpConfig[0].IsUsed));
  DEBUG ((EFI_D_INFO, "Config->X100DpConfig[1].DownSpreadEnable : %x\n", X100ConfigData.X100DpConfig[1].DownSpreadEnable));
  DEBUG ((EFI_D_INFO, "Config->X100DpConfig[1].IsUsed : %x\n", X100ConfigData.X100DpConfig[1].IsUsed));
  DEBUG ((EFI_D_INFO, "Config->X100DpConfig[2].DownSpreadEnable : %x\n", X100ConfigData.X100DpConfig[2].DownSpreadEnable));
  DEBUG ((EFI_D_INFO, "Config->X100DpConfig[2].IsUsed : %x\n", X100ConfigData.X100DpConfig[2].IsUsed));
  DEBUG ((EFI_D_INFO, "Pcie x2-0 Enable : %d\n", X100ConfigData.PcieX2Dn4Enable));
  DEBUG ((EFI_D_INFO, "Pcie x2-1 Enable : %d\n", X100ConfigData.PcieX2Dn5Enable));
  DEBUG ((EFI_D_INFO, "Pcie x1-0 Enable : %d\n", X100ConfigData.PcieX1Dn6Enable));
  DEBUG ((EFI_D_INFO, "Pcie x1-1 Enable : %d\n", X100ConfigData.PcieX1Dn7Enable));
  DEBUG ((EFI_D_INFO, "Pcie x1-2 Enable : %d\n", X100ConfigData.PcieX1Dn8Enable));
  DEBUG ((EFI_D_INFO, "Pcie x1-3 Enable : %d\n", X100ConfigData.PcieX1Dn9Enable));
  for (Index = 0; Index < NumOfPciHandles; Index ++) {
    Status = gBS->HandleProtocol (
                    HandleBuffer[Index],
                    &gEfiPciIoProtocolGuid,
                    (VOID **)&PciIo
                    );
    if (!EFI_ERROR (Status)) {
      PciIo->Pci.Read (
                   PciIo,
                   EfiPciIoWidthUint16,
                   0x0,
                   1,
                   &VendorID
                   );
      PciIo->Pci.Read (
                   PciIo,
                   EfiPciIoWidthUint16,
                   0x2,
                   1,
                   &DeviceID
                   );
      //DEBUG ((EFI_D_INFO, "Device ID : 0x%04x, Vendor ID : 0x%04x\n", DeviceID, VendorID));
      if ((DeviceID == 0xdc3a) && (VendorID == 0x1db7)) {
        X100PciInfo.X100IsExisted = 1;
        PciIo->GetLocation (PciIo, &Seg, &Bus, &Dev, &Func);
        //DEBUG  ((EFI_D_INFO, "----------------------\n"));
        //DEBUG  ((EFI_D_INFO, "bus : %d\n", Bus));
        //DEBUG  ((EFI_D_INFO, "device : %d\n", Dev));
        //DEBUG  ((EFI_D_INFO, "function : %d\n", Func));
        //DEBUG  ((EFI_D_INFO, "----------------------\n"));
        switch (Dev) {
        //display
        case 1:
          X100PciInfo.DisplaySwitch.Enable = X100ConfigData.DisplayEnable;
          X100PciInfo.DisplaySwitch.Seg = Seg;
          X100PciInfo.DisplaySwitch.Bus = Bus;
          X100PciInfo.DisplaySwitch.Dev = Dev;
          X100PciInfo.DisplaySwitch.Func = Func;
          if (X100ConfigData.DisplayEnable == 0) {
            SetDevicePowerState (PciIo, 3);
            gBS->Stall (50 * 1000);
          }
          break;
        //usb
        case 2:
          X100PciInfo.UsbSwitch.Enable = X100ConfigData.UsbEnable;
          X100PciInfo.UsbSwitch.Seg = Seg;
          X100PciInfo.UsbSwitch.Bus = Bus;
          X100PciInfo.UsbSwitch.Dev = Dev;
          X100PciInfo.UsbSwitch.Func = Func;
          if (X100ConfigData.UsbEnable == 0) {
            SetDevicePowerState (PciIo, 3);
            gBS->Stall (50 * 1000);
          }
          break;
        //sata
        case 3:
          X100PciInfo.SataSwitch.Enable = X100ConfigData.SataEnable;
          X100PciInfo.SataSwitch.Seg = Seg;
          X100PciInfo.SataSwitch.Bus = Bus;
          X100PciInfo.SataSwitch.Dev = Dev;
          X100PciInfo.SataSwitch.Func = Func;
          if (X100ConfigData.SataEnable == 0) {
            SetDevicePowerState (PciIo, 3);
            gBS->Stall (50 * 1000);
          }
          break;
        case 4:
          if (X100ConfigData.PcieX2Dn4Enable == 0) {
            SetDevicePowerState (PciIo, 3);
            gBS->Stall (50 * 1000);
          }
          break;
        case 5:
          if (X100ConfigData.PcieX2Dn5Enable == 0) {
            SetDevicePowerState (PciIo, 3);
            gBS->Stall (50 * 1000);
          }
          break;
        case 6:
          if (X100ConfigData.PcieX1Dn6Enable == 0) {
            SetDevicePowerState (PciIo, 3);
            gBS->Stall (50 * 1000);
          }
          break;
        case 7:
          if (X100ConfigData.PcieX1Dn7Enable == 0) {
            SetDevicePowerState (PciIo, 3);
            gBS->Stall (50 * 1000);
          }
          break;
        case 8:
          if (X100ConfigData.PcieX1Dn8Enable == 0) {
            SetDevicePowerState (PciIo, 3);
            gBS->Stall (50 * 1000);
          }
          break;
        case 9:
          if (X100ConfigData.PcieX1Dn9Enable == 0) {
            SetDevicePowerState (PciIo, 3);
            gBS->Stall (50 * 1000);
          }
          break;
        default:
          break;
        }
      }
      //
      //display
      //
      if ((DeviceID == 0xdc22) && (VendorID == 0x1db7)) {
        SetX100ConfigToDc (&X100ConfigData, PciIo);
      }
      //
      //Sata Control
      //
      SataPi = 0;
      if ((DeviceID == 0xdc26) && (VendorID == 0x1db7)) {
        PciIo->Pci.Read (
                     PciIo,
                     EfiPciIoWidthUint8,
                     0x2E,
                     1,
                     &Temp
                     );
        //test
        //Temp = 0xF;
        DEBUG ((EFI_D_INFO, "X100 Sata used : %x\n", Temp));
        //test
        for (Num = 0; Num < 4; Num++) {
          X100ConfigData.SataPort[Num].IsUsed = (Temp >> Num) & 0x1;
          if (X100ConfigData.SataPort[Num].IsUsed == 0) {
            X100ConfigData.SataPort[Num].Enable = 0;
          }
          DEBUG ((EFI_D_INFO, "X100 Sata Port[%d] Used : %d, Enable : %d\n", Num,
                      X100ConfigData.SataPort[Num].IsUsed, X100ConfigData.SataPort[Num].Enable));
          SataPi |= ((X100ConfigData.SataPort[Num].Enable & 0x1) << Num);
        }
        DEBUG ((EFI_D_INFO, "X100 Sata Pi : %0x\n", SataPi));
        Temp = 0x03;
        PciIo->Pci.Write (
                     PciIo,
                     EfiPciIoWidthUint8,
                     0x4,
                     1,
                     &Temp
                     );
        PciIo->Mem.Write (
                     PciIo,
                     EfiPciIoWidthUint32,
                     5,
                     0xC,
                     1,
                     &SataPi
                     );
        Temp = 0x0;
        PciIo->Pci.Write (
                     PciIo,
                     EfiPciIoWidthUint8,
                     0x4,
                     1,
                     &Temp
                     );
      }
    }
  }
  Status = gRT->SetVariable (
                  VAR_X100_PCI_INFO,
                  &gX100PciInfoVarGuid,
                  PLATFORM_SETUP_VARIABLE_FLAG,
                  sizeof (X100_PCI_INFO),
                  &X100PciInfo
                  );
  ASSERT_EFI_ERROR(Status);

  Status = gRT->SetVariable (
                  VAR_X100_CONFIG,
                  &gAdvancedX100VarGuid,
                  PLATFORM_SETUP_VARIABLE_FLAG,
                  VarSize,
                  &X100ConfigData
                  );
  ASSERT_EFI_ERROR(Status);

  return EFI_SUCCESS;
}
#else
EFI_STATUS
ControlX100DevEnable(
  IN SYSTEM_SETUP_CONFIGURATION  *Configuration
)
{
  UINT32                    Status;
  UINTN                     NumOfPciHandles;
  EFI_HANDLE*               HandleBuffer;
  EFI_PCI_IO_PROTOCOL*      PciIo;
  UINT32                    Index;
  UINT16                    DeviceID;
  UINT16                    VendorID;
  UINTN                     Seg;
  UINTN                     Bus;
  UINTN                     Func;
  UINTN                     Dev;
  EFI_DEVICE_PATH_PROTOCOL* DevicePath;
  UINTN                     StrLength;
  BOOLEAN                   FoundUsbDevice;
  UINTN                     Count;
  CHAR16*                   UsbText = NULL;
  UINTN                     BufferSize = 0;
  UINT16                    LocalFlag;
  UINT16                    VarChangeFlag;
  UINT16                    Num;
  UINT16                    SumNum;
  X100_CONFIG *             X100ConfigVar;//[gliu-0031]
  UINT32                    SataPi;
  UINT8                     Temp;
  //[gliu-0009]
  SYSTEM_SETUP_CONFIGURATION        *SetupVar = Configuration;
  EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *mDevPathToText = NULL;
  CHAR16                           mUsbMsTable[TOTAL_USB_MS_NUMBER][PATH_TEXT_LENGTH];
  CHAR16                           mUsbKbTable[TOTAL_USB_MS_NUMBER][PATH_TEXT_LENGTH];
  UINTN                            mUsbKbNumber = 0;
  UINTN                            mUsbMsNumber = 0;
  //[gliu-0009]

  if (SetupVar->X100Config.X100IsExisted == 0) {
    return EFI_SUCCESS;
  }


  LocalFlag = 0;
  Status = 0;
  NumOfPciHandles = 0;
  HandleBuffer = NULL;
  FoundUsbDevice = FALSE;
  VarChangeFlag = 0;
  Status = gBS->LocateHandleBuffer(
      ByProtocol,
      &gEfiPciIoProtocolGuid,
      NULL,
      &NumOfPciHandles,
      &HandleBuffer);
  if (EFI_ERROR(Status)) {
    return Status;
  }

  X100ConfigVar = AllocatePool(sizeof(X100_CONFIG));//[gliu-0031]
  if (X100ConfigVar == 0) {
    DEBUG((EFI_D_ERROR, "X100 allocate is fail!\n"));
    return -1;
  }
  SetupVar->X100Config.DisplayEnable = 1;
  SetupVar->USBController = 1;
  SetupVar->X100Config.UsbEnable = 1;
  
  CopyMem(X100ConfigVar,
      &SetupVar->X100Config,
      sizeof(X100_CONFIG));//[gliu-0031]

  for (Index = 0; Index < NumOfPciHandles; Index++) {
    Status = gBS->HandleProtocol(
        HandleBuffer[Index],
        &gEfiPciIoProtocolGuid,
        (VOID**)&PciIo);
    if (!EFI_ERROR(Status)) {
      PciIo->Pci.Read(
          PciIo,
          EfiPciIoWidthUint16,
          0x0,
          1,
          &VendorID);
      PciIo->Pci.Read(
          PciIo,
          EfiPciIoWidthUint16,
          0x2,
          1,
          &DeviceID);
      DEBUG((EFI_D_INFO, "Device ID-: 0x%04x, Vendor ID : 0x%04x\n", DeviceID, VendorID));
      if ((DeviceID == 0xdc3a) && (VendorID == 0x1db7)) {
        PciIo->GetLocation(PciIo, &Seg, &Bus, &Dev, &Func);
        DEBUG((EFI_D_INFO, "----------------------\n"));
        DEBUG((EFI_D_INFO, "bus : %d\n", Bus));
        DEBUG((EFI_D_INFO, "device : %d\n", Dev));
        DEBUG((EFI_D_INFO, "function : %d\n", Func));
        DEBUG((EFI_D_INFO, "----------------------\n"));
        switch (Dev) {
        // display
        case 1:
          LocalFlag = 0;
          if (SetupVar->X100Config.DisplayEnable == 0) {
            LocalFlag = 1;
          }
          if (LocalFlag > 0) {
            LocalFlag = 0;
            SetDevicePowerState(PciIo, 3);
            gBS->Stall(50 * 1000);
          }
          break;
        // usb
        case 2:
          LocalFlag = 0;
          if (SetupVar->USBController == 0) {
            LocalFlag = 1;
          } else {
            if (SetupVar->X100Config.UsbEnable == 0) {
              LocalFlag = 1;
            }
          }

          if (LocalFlag > 0) {
            LocalFlag = 0;
            ZeroMem(mUsbMsTable, TOTAL_USB_MS_NUMBER * PATH_TEXT_LENGTH * sizeof(CHAR16));
            ZeroMem(mUsbKbTable, TOTAL_USB_KB_NUMBER * PATH_TEXT_LENGTH * sizeof(CHAR16));

            BufferSize = sizeof(UINT8);
            Status = gRT->GetVariable(
                L"UsbMsNum",
                &gEfiUsbKbMsLabelGuid,
                NULL,
                &BufferSize,
                &mUsbMsNumber);

            if ((!EFI_ERROR(Status)) && (mUsbMsNumber > 0)) {
              BufferSize = sizeof(CHAR16) * TOTAL_USB_MS_NUMBER * PATH_TEXT_LENGTH;
              Status = gRT->GetVariable(
                  L"UsbMsInfo",
                  &gEfiUsbKbMsLabelGuid,
                  NULL,
                  &BufferSize,
                  &mUsbMsTable);
            }

            BufferSize = sizeof(UINT8);
            Status = gRT->GetVariable(
                L"UsbKbNum",
                &gEfiUsbKbMsLabelGuid,
                NULL,
                &BufferSize,
                &mUsbKbNumber);

            if ((!EFI_ERROR(Status)) && (mUsbKbNumber > 0)) {
              BufferSize = sizeof(CHAR16) * TOTAL_USB_KB_NUMBER * PATH_TEXT_LENGTH;
              Status = gRT->GetVariable(
                  L"UsbKbInfo",
                  &gEfiUsbKbMsLabelGuid,
                  NULL,
                  &BufferSize,
                  &mUsbKbTable);
              DEBUG((EFI_D_INFO, "Get UsbKbInfo status: %r\n", Status));
            }

            Status = gBS->HandleProtocol(
                HandleBuffer[Index],
                &gEfiDevicePathProtocolGuid,
                (VOID**)&DevicePath);
            if (EFI_ERROR(Status)){
              return Status;
            }
            Status = gBS->LocateProtocol(
                &gEfiDevicePathToTextProtocolGuid,
                NULL,
                (VOID**)&mDevPathToText);
            if (EFI_ERROR(Status)){
              return Status;
            }
            UsbText = mDevPathToText->ConvertDevicePathToText(
                DevicePath,
                FALSE,
                TRUE);
            StrLength = StrLen(UsbText);

            for (Count = 0; Count < mUsbKbNumber; Count++) {
              if (StrnCmp(mUsbKbTable[Count], UsbText, StrLength) == 0) {
                FoundUsbDevice = TRUE;
                break;
              }
            }

            for (Count = 0; Count < mUsbMsNumber; Count++) {
              if (StrnCmp(mUsbMsTable[Count], UsbText, StrLength) == 0) {
                FoundUsbDevice = TRUE;
                break;
              }
            }

            if (FoundUsbDevice == FALSE) {
              SetDevicePowerState(PciIo, 3);
              gBS->Stall(50 * 1000);
            } else {
              SetupVar->USBController = 1;
              SetupVar->X100Config.UsbEnable = 1;
              VarChangeFlag = 1;
            }
          }
          break;
        // sata
        case 3:
          LocalFlag = 0;
          if (0) {
            LocalFlag = 1;
          } else {
            if (0) {
              LocalFlag = 1;
            }
          }

          if (LocalFlag > 0) {
            LocalFlag = 0;
            SetDevicePowerState(PciIo, 3);
            gBS->Stall(50 * 1000);
          }
          break;
        case 4:
          if (SetupVar->X100Config.PcieX2Dn4Enable == 0) {
            SetDevicePowerState (PciIo, 3);
            gBS->Stall (50 * 1000);
          }
          break;
        case 5:
          if (SetupVar->X100Config.PcieX2Dn5Enable == 0) {
            SetDevicePowerState (PciIo, 3);
            gBS->Stall (50 * 1000);
          }
          break;
        case 6:
          if (SetupVar->X100Config.PcieX1Dn6Enable == 0) {
            SetDevicePowerState (PciIo, 3);
            gBS->Stall (50 * 1000);
          }
          break;
        case 7:
          if (SetupVar->X100Config.PcieX1Dn7Enable == 0) {
            SetDevicePowerState (PciIo, 3);
            gBS->Stall (50 * 1000);
          }
          break;
        case 8:
          if (SetupVar->X100Config.PcieX1Dn8Enable == 0) {
            SetDevicePowerState (PciIo, 3);
            gBS->Stall (50 * 1000);
          }
          break;
        case 9:
          if (SetupVar->X100Config.PcieX1Dn9Enable == 0) {
            SetDevicePowerState (PciIo, 3);
            gBS->Stall (50 * 1000);
          }
          break;
        default:
          break;
        }
      }
      //
      //display
      //
      if ((DeviceID == 0xdc22) && (VendorID == 0x1db7)) {
        SetX100ConfigToDc (&SetupVar->X100Config, PciIo);
      }
      //
      // SATA Controller
      //
      SataPi = 0;
      if ((DeviceID == 0xdc26) && (VendorID == 0x1db7)) {
        SumNum = sizeof(X100ConfigVar->SataPort) / sizeof(X100ConfigVar->SataPort[0]);
        PciIo->Pci.Read(
            PciIo,
            EfiPciIoWidthUint8,
            0x2E,
            1,
            &Temp);
        DEBUG((EFI_D_INFO, "X100 Sata used : %x\n", Temp));
        if (0) {
          //  SATA Controller close
        } else {
          if (0) {
            //  SATA Controller close
            //ZeroMem(X100ConfigVar->SataPort, sizeof(X100ConfigVar->SataPort));
          } else {
            // SATA Controller open
            for (Num = 0; Num < SumNum; Num++) {
              SetupVar->X100Config.SataPort[Num].IsUsed = (Temp >> Num) & 0x1;
              if (SetupVar->X100Config.SataPort[Num].IsUsed == 0) {
                SetupVar->X100Config.SataPort[Num].Enable = 0;
              } else {
                SetupVar->X100Config.SataPort[Num].Enable = 1;
              }
              DEBUG((EFI_D_INFO, "X100 Sata Port[%d] Used : %d, Enable : %d\n",
                      Num,
                      SetupVar->X100Config.SataPort[Num].IsUsed,
                      SetupVar->X100Config.SataPort[Num].Enable));
              SataPi |= ((SetupVar->X100Config.SataPort[Num].Enable & 0x1) << Num);
            }
            DEBUG((EFI_D_INFO, "X100 Sata Pi : %0x\n", SataPi));
            Temp = 0x03;
            PciIo->Pci.Write(
                PciIo,
                EfiPciIoWidthUint8,
                0x4,
                1,
                &Temp);
            PciIo->Mem.Write(
                PciIo,
                EfiPciIoWidthUint32,
                5,
                0xC,
                1,
                &SataPi);
            Temp = 0x0;
            PciIo->Pci.Write(
                PciIo,
                EfiPciIoWidthUint8,
                0x4,
                1,
                &Temp);
          }
        }
      }
    }
  }
  // Judge whether the storage parameters change
  if (CompareMem(X100ConfigVar,
          &SetupVar->X100Config,
          sizeof(X100_CONFIG))//[gliu-0031]
      != 0) {
    VarChangeFlag = 1;
  }
  // Variable changes need to be stored in Flash
  if (VarChangeFlag > 0) {
    VarChangeFlag = 0;
  //[gliu-0009]
  /*
    Status = gRT->SetVariable(
        SETUP_VARIABLE_NAME,
        &gSystemConfigurationGuid,
        EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
        sizeof(SYSTEM_SETUP_CONFIGURATION),
        SetupVar);*/
     Status = KlSetupVarWrite(SetupVar);
  //[gliu-0009]
  }
  // Free memory
  if (X100ConfigVar) {
    FreePool(X100ConfigVar);
  }
  if (HandleBuffer) {
    gBS->FreePool(HandleBuffer);
  }
  //[gliu-0009]
  //if(SetupVar){
  //    FreePool(SetupVar);
  //}
  //[gliu-0009]
  return Status;
}
#endif

EFI_STATUS
ModifyPciRootPortTag (
  IN SYSTEM_SETUP_CONFIGURATION  *Configuration
  )
{
  UINT32                      Status;
  UINTN                       NumOfPciHandles;
  EFI_HANDLE                  *HandleBuffer;
  EFI_PCI_IO_PROTOCOL         *PciIo;
  UINT32                      Index;
  UINT16                      DeviceID;
  UINT16                      VendorID;

  if(Configuration->X100Config.X100IsExisted == 0) {
    return EFI_SUCCESS;
  }
  Status = 0;
  NumOfPciHandles = 0;
  HandleBuffer = NULL;

  //modify pci rootport tag only x100 is existed.
  //if (IsX100Existed () == 0) {
  //  return EFI_SUCCESS;
  //}

  Status = gBS->LocateHandleBuffer (
                  ByProtocol,
                  &gEfiPciIoProtocolGuid,
                  NULL,
                  &NumOfPciHandles,
                  &HandleBuffer
                  );
  if (EFI_ERROR (Status)) {
    return 0;
  }

  DEBUG ((EFI_D_INFO, "ModifyPciRootPortTag:Pci handles number is %d\n", NumOfPciHandles));

  for (Index = 0; Index < NumOfPciHandles; Index ++) {
    Status = gBS->HandleProtocol (
                    HandleBuffer[Index],
                    &gEfiPciIoProtocolGuid,
                    (VOID **)&PciIo
                    );
    if (!EFI_ERROR (Status)) {
      PciIo->Pci.Read (
                   PciIo,
                   EfiPciIoWidthUint16,
                   0x0,
                   1,
                   &VendorID
                   );
      PciIo->Pci.Read (
                   PciIo,
                   EfiPciIoWidthUint16,
                   0x2,
                   1,
                   &DeviceID
                   );

      if (VendorID == 0x17CD) {
        UINT8  Temp;
        UINT32 PciExpressCapabilityOffset = 0x80;
        PciIo->Pci.Read (
                     PciIo,
                     EfiPciIoWidthUint8,
                     PciExpressCapabilityOffset + 0x09,
                     1,
                     &Temp
                     );
        Temp &= 0xFE;
        PciIo->Pci.Write (
                     PciIo,
                     EfiPciIoWidthUint8,
                     PciExpressCapabilityOffset + 0x09,
                     1,
                     &Temp
                     );
        }
      }
    }
    return EFI_SUCCESS;
  }
  #endif